////////////////////////////////////////////////////////////////////
// Programme de reinsertion des fichiers de Chrono Cross
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// Nemesis pour Terminus Traduction (tt_nemesis@yahoo.fr)
// Date de création :		01/08/03
// Dernière modification :	02/04/04
////////////////////////////////////////////////////////////////////
// Ce fichier est le clone de celui de Dump aux accès près

// Entete
#include "Reinsertion.h"

// Type de données pour les Rooms
typedef struct {
	char *nom;
	unsigned _int32 adr;
	unsigned _int8 fin;
	unsigned _int8 nb;
} Reinsertion_TRoom;

// Noms des fichiers
Reinsertion_TRoom Reinsertion_Rooms[REIN_ROOMS_NB];
// Nombres de fichiers
_int16 Reinsertion_Rooms_Nb;

// Secteurs des adresses de fichiers
_int32 Reinsertion_Secteur_Entete=0;

/*------------------------------------------------------------------
  Initialisation du la reinsertion de fichiers
--------------------------------------------------------------------
 Cette fonction est absolument identique à Dump_Initialisation
------------------------------------------------------------------*/
void Reinsertion_Initialisation (void)
{
	// Fichier des infos
	FILE *infos_f;
	// Nom de l'iso (chemin)
	char infos_nom[REIN_NOM_MAX];
	// Numero de fichier
	int room_deb,room_fin,r;
	// Nom de fichier
	char room_nom_complet[REIN_ROOMS_NOM];
	char room_nom[REIN_ROOMS_NOM];
	char room_ext[4];
	// Ligne
	char ligne[REIN_LIGNE_MAX];
	// Nombre de champs d'infos
	int result;

	Main_Message_S("Initialisation de reinsertion... ","",OK);
	// Ouverture du fichier des infos principales
	sprintf(infos_nom,"%s%s.%s",DIR_INFOS,INFOS_FICH,EXT_INFOS);
	infos_f=fopen(infos_nom,"rb");

	if (infos_f==NULL)
		Main_Message_S("Erreur d'ouverture.\n","",ER);
	else {
		// Operations non protegées
		// Récupération du secteur des pointeurs
		fscanf(infos_f,"%d",&Reinsertion_Secteur_Entete);
		// Récupération du nombre de fichiers
		fscanf(infos_f,"%d",&Reinsertion_Rooms_Nb);
		// Passage à la ligne suivante
		fgets(ligne,REIN_LIGNE_MAX,infos_f);
		// Récupération des noms de fichiers
		while (fgets(ligne,REIN_LIGNE_MAX,infos_f)!=NULL)
			// Cas d'un commentaire ou d'un blanc
			if (ligne[0]!=COMMENT) {
				result=sscanf(ligne,"%d-%d %3s %s",
					&room_deb,&room_fin,room_ext,room_nom);
				switch (result) {
				case 4:
					sprintf(room_nom_complet,
						" (%s).%s",room_nom,room_ext);
					break;
				case 3:
					sprintf(room_nom_complet,
						".%s",room_ext);
					break;
				case 2:
					sprintf(room_nom_complet,
						".%s",EXT_DUMP);
					break;
				default:
					Main_Message_S("Info erronee... ","",ER);
				}
				if (result>1)
					for(r=room_deb;r<=room_fin;r++)
						Reinsertion_Rooms[r].nom=strdup(room_nom_complet);
			}
		// Fermeture du fichier des infos
		fclose(infos_f);
	}
	Main_OK();
}

/*------------------------------------------------------------------
  Dump des infos de fichiers pointés par Reinsertion_Secteur_Entete
--------------------------------------------------------------------
 Cette fonction est absolument identique à Dump_Pointeurs
------------------------------------------------------------------*/
void Reinsertion_Pointeurs (void)
{
	// Numero de pointeur
	_int16 ptr=0;
	_int16 p;
	// Lecture de l'adresse avant traitement
	unsigned _int32 buffer[SECTEUR_DONNEES/4];

	Main_Message_S("Recup des informations des fichiers... ","",OK);
	// Placement sur la table d'adresses
	Iso_Secteur_Saut(Reinsertion_Secteur_Entete);
	while(ptr<Reinsertion_Rooms_Nb) {
		// Changement de secteur
		Iso_Entete_Lit(NON);
		Iso_Adresses_Lit(buffer);
		// Traitement des adresses
		for(p=0;p<(SECTEUR_DONNEES/4);p++) {
			// Plusieurs pointeurs identiques au 0x00800000 près
			Reinsertion_Rooms[ptr].nb++;
			// Test du bit de poids fort du 2ème octet (0=ok)
			if (!(buffer[p] & 0x00800000)) {
				Reinsertion_Rooms[ptr].fin=(unsigned _int8)(buffer[p]>>24);
				Reinsertion_Rooms[ptr].adr=(buffer[p]<<8)>>8;
				ptr++;
			}
		}
		Iso_ECC_Saut();
	};
	Main_OK();
}

/*------------------------------------------------------------------
  Réinsertion des infos des fichiers pointés
--------------------------------------------------------------------
 Cette fonction gère la modification des pointeurs de fichiers
 Elle est là pour pouvoir modifier la forme de l'iso en sortie,
 ce qui n'est pas encore implémenté.
------------------------------------------------------------------*/
void Reinsertion_Pointeurs_Modif (void)
{
	// Numero de pointeur
	_int16 ptr=0;
	_int16 p,n=0;
	// Lecture de l'adresse avant traitement
	unsigned _int32 buffer[SECTEUR_DONNEES/4];

	Main_Message_S("Reinsertion des informations des fichiers... ","",OK);
	// Placement sur la table d'adresses
	Iso_Secteur_Saut(Reinsertion_Secteur_Entete);
	while(ptr<Reinsertion_Rooms_Nb) {
		// Changement de secteur
		Iso_Entete_Lit(NON);
		// Traitement des adresses
		for(p=0;p<(SECTEUR_DONNEES/4);p++) {
			buffer[p]=Reinsertion_Rooms[ptr].adr;
			// Cas de plusieurs pointeurs identiques
			if (n<Reinsertion_Rooms[ptr].nb-1) {
				buffer[p]|=0x00800000;
				n++;
			} else {
				buffer[p]+=Reinsertion_Rooms[ptr].fin<<24;
				n=0;
				ptr++;
			}
		}
		Iso_Flush();
		Iso_Adresses_Ecrit(buffer);
		//Iso_ECC_Saut();
	};
	Main_OK();
}

/*------------------------------------------------------------------
  Réinsertion d'un fichier (appelé par Dump_Exec)
  la fonction assume que l'iso est déjà ouverte en lecture
--------------------------------------------------------------------
 <- room_num = fichier en question déterminé par son numéro
	dans la table des fichiers
------------------------------------------------------------------*/
void Reinsertion_Room (unsigned _int16 room_num)
{
	// Infos de lecture du fichier
	_int32 taille,pos;
	_int32 sects,sects_max;
	// Fichier Room de sortie
	FILE *room_f;
	// Nom du fichier (chemin)
	char room_nom[REIN_NOM_MAX];
	// Débordement
	int debord;

	// Test du paramètre
	if (room_num<0 || room_num>Reinsertion_Rooms_Nb)
		Main_Message_D("Room %d inexistante.\n",room_num,ER);
	else {
		// Evaluation du nom de fichier
		if (Reinsertion_Rooms[room_num].nom==NULL)
			sprintf(room_nom,"%s%04d.%s",
				DIR_DUMP_OUT,room_num,EXT_REIN);
		else
			sprintf(room_nom,"%s%04d%s",DIR_DUMP_OUT,room_num,
				Reinsertion_Rooms[room_num].nom);
		// Completion du fichier room
		Fichier_Completer(room_nom);
		// Ouverture du fichier room
		room_f=fopen(room_nom,"rb");

		if (room_f==NULL)
			Main_Message_S("Fichier introuvable.\n","",ER);
		else {
			// Taille du fichier d'entrée
			fseek(room_f,0L,SEEK_END);
			taille = ftell(room_f);
			sects = (taille+SECTEUR_DONNEES-1)/SECTEUR_DONNEES;
			fseek(room_f,0L,SEEK_SET);
			// Attention au cas du dernier fichier
			if (room_num==Reinsertion_Rooms_Nb)
				sects_max = sects;
			else
				sects_max = Reinsertion_Rooms[room_num+1].adr
					    - Reinsertion_Rooms[room_num].adr;
			// Calcul de débordement
			debord=sects-sects_max;
			// Test de débordement
			if (debord<0) {
				Main_Message_D("Decalage negatif en %04d",room_num,OK);
				Main_Message_D(" de %d.\n",sects_max*SECTEUR_DONNEES-taille,OK);
			} else if (debord>0) {
				Main_Message_D("Decalage positif en %04d",room_num,OK);
				Main_Message_D(" de %d.\n",taille-sects_max*SECTEUR_DONNEES,OK);
			}
			// Demande de confirmation pour le décalage
			if (debord<=0) { // || getch()=='o') { // Le <= est en test
				/* Mise à jour de l'adresse du fichier suivant
				Reinsertion_Rooms[room_num+1].adr=
					Reinsertion_Rooms[room_num].adr+sects;*/
				// Placement en début de fichier
				Iso_Secteur_Saut(Reinsertion_Rooms[room_num].adr);
				// Parcours du fichier
				pos=SECTEUR_DONNEES;
				while (pos<taille) {
					Iso_Entete_Modif(SECT_TFICH);
					Iso_Donnees_Insere(room_f);
					//Iso_ECC_Saut();
					pos+=SECTEUR_DONNEES;
				}
				Iso_Entete_Modif(SECT_TFIN);
				Iso_Donnees_Insere(room_f);
				// Mise à jour de la "taille de fin" du fichier
				Reinsertion_Rooms[room_num].fin=
					(pos - taille)/8;
			}
			fclose(room_f);
		}
	}
}

/*------------------------------------------------------------------
  Reinsertion d'un ensemble de fichiers
--------------------------------------------------------------------
 <- rooms = ensemble des fichiers déterminés par des délimiteurs
	exemple : 1-4;5;8 = fichiers 1->5 + 8
------------------------------------------------------------------*/
void Reinsertion_Exec (char* rooms)
{
	// Numéros des Rooms à extraire
	char* room_intervals[REIN_ROOMS_INTER];
	int interval,i;
	// Type d'intervalle
	int result;
	// Bornes
	unsigned _int16 room_deb,room_fin,r;

	Main_Message_S("Reinsertion des fichiers %s en cours... ",rooms,OK);

	// Décomposition des rooms en intervalles
	interval=0; // intervalle actuel
	room_intervals[interval]=strtok(rooms,";");
	do
		interval++;
	while((room_intervals[interval]=strtok(NULL,";"))!=NULL);

	// Extension des intervalles
	for(i=0;i<interval;i++) {
		result=sscanf(room_intervals[i],"%d-%d",
			&room_deb,&room_fin);
		switch (result) {
		case 1:
			Reinsertion_Room(room_deb);
			break;
		case 2:
			for (r=room_deb;r<=room_fin;r++)
				Reinsertion_Room(r);
			break;
		default:
			Main_Message_D("Erreur dans l'intervalle %d.\n",i+1,ER);
		}
	}
	Main_OK();
}
